package analyse

import (
	"github.com/shopspring/decimal"
	"github.com/yejingxuan/accumulate/infrastructure/config"
)

var (
	TagBigVolume        = "BigVolume"           //量价齐升
	TagGreatVolume      = "GreatVolume"         //巨量成交
	TagNearMA60         = "NearMA60"            //60日线附近（上方）
	TagBackToMA60       = "BackToMA60"          //回踩60日线
	TagNearLowest30     = "NearLowest30"        //30天最低价附近
	TagDojiLine         = "TagDojiLine"         //十字星
	TagContinueDojiLine = "TagContinueDojiLine" //连续十字星
)

var CalculateTags = map[TagInfo]func([]BaseAnalyseInfo) bool{
	TagInfo{TagBigVolume, "量价齐升"}:         CalculateBigVolume,
	TagInfo{TagGreatVolume, "巨量成交"}:       CalculateGreatVolume,
	TagInfo{TagNearMA60, "60日线附近"}:        CalculateNearMA60,
	TagInfo{TagBackToMA60, "回踩60日线"}:      CalculateTagBackToMA60,
	TagInfo{TagNearLowest30, "30日最低价附近"}:  CalculateTagNearLowest30,
	TagInfo{TagDojiLine, "十字星"}:           CalculateTagDojiLine,
	TagInfo{TagContinueDojiLine, "连续十字星"}: CalculateTagContinueDojiLine,
}

type TagInfo struct {
	Value string
	Desc  string
}

/**计算量价齐升
1.当天比前5天平均成交量高80%
2.当天涨幅超过3%
*/
func CalculateBigVolume(baseInfo []BaseAnalyseInfo) bool {
	if len(baseInfo) < 30 {
		return false
	}
	compareCount := 5
	todayInfo := baseInfo[len(baseInfo)-1]
	//量升价不升，pass掉
	if todayInfo.Percent < 3 {
		return false
	}

	volumeArray := make([]float64, 0)
	for i := len(baseInfo) - compareCount - 1; i < len(baseInfo)-1; i++ {
		volumeArray = append(volumeArray, baseInfo[i].Volume)
	}

	avgVolume := CalculateAvg(volumeArray)

	percent := decimal.NewFromFloat(todayInfo.Volume).Div(decimal.NewFromFloat(avgVolume))
	if cmp := percent.Cmp(decimal.NewFromFloat(1.8)); cmp == -1 {
		return false
	}
	return true
}

/**巨量成交
1.当天成交量是前五天的2倍以上
*/
func CalculateGreatVolume(baseInfo []BaseAnalyseInfo) bool {
	compareCount := 5
	if len(baseInfo) <= compareCount {
		return false
	}

	todayInfo := baseInfo[len(baseInfo)-1]
	volumeArray := make([]float64, 0)
	for i := len(baseInfo) - compareCount - 1; i < len(baseInfo)-1; i++ {
		volumeArray = append(volumeArray, baseInfo[i].Volume)
	}
	avgVolume := CalculateAvg(volumeArray)
	percent := decimal.NewFromFloat(todayInfo.Volume).Div(decimal.NewFromFloat(avgVolume))
	if cmp := percent.Cmp(decimal.NewFromInt(config.CoreConf.Server.Calculate.GreatVolumeVal)); cmp == -1 {
		return false
	}
	return true
}

/**计算最近是否突破60日线
1.当天价格在60日上方5%左右
*/
func CalculateNearMA60(baseInfo []BaseAnalyseInfo) bool {
	if len(baseInfo) < 30 {
		return false
	}
	todayInfo := baseInfo[len(baseInfo)-1]
	percent := decimal.NewFromFloat(todayInfo.Close).Div(decimal.NewFromFloat(todayInfo.MA60))
	cmp1 := percent.Cmp(decimal.NewFromFloat(1.05))
	cmp2 := percent.Cmp(decimal.NewFromFloat(0.95))
	if cmp1 == -1 && cmp2 == 1 {
		return true
	}
	return false
}

/**计算回踩60日线
1.前8天，有5天以上的价格都在ma60上0-10%
2.前20天，有10天以上在ma60下
3.当天价格在60日线上%5左右
*/
func CalculateTagBackToMA60(baseInfo []BaseAnalyseInfo) bool {
	if len(baseInfo) < 20 {
		return false
	}
	upCompareCount := 8
	upTotalDay := 0
	for i := len(baseInfo) - upCompareCount; i < len(baseInfo); i++ {
		percent := decimal.NewFromFloat(baseInfo[i].Close).Div(decimal.NewFromFloat(baseInfo[i].MA60))
		cmp1 := percent.Cmp(decimal.NewFromFloat(1.1))
		cmp2 := percent.Cmp(decimal.NewFromFloat(1.00))
		if cmp1 == -1 && cmp2 == 1 {
			upTotalDay++
		}
	}

	downCompareCount := 20
	downTotalDay := 0
	for i := len(baseInfo) - downCompareCount; i < len(baseInfo); i++ {
		percent := decimal.NewFromFloat(baseInfo[i].Close).Div(decimal.NewFromFloat(baseInfo[i].MA60))
		cmp1 := percent.Cmp(decimal.NewFromFloat(1.00))
		if cmp1 == -1 {
			downTotalDay++
		}
	}

	if upTotalDay >= 5 && downTotalDay >= 10 && CalculateNearMA60(baseInfo) {
		return true
	}

	return false
}

/**计算是否在30天最低价附近
1.当天价格在30天最低价0-5%波动
*/
func CalculateTagNearLowest30(baseInfo []BaseAnalyseInfo) bool {
	if len(baseInfo) < 30 {
		return false
	}
	todayInfo := baseInfo[len(baseInfo)-1]
	lowest30Price := todayInfo.Close

	for i := 0; i < len(baseInfo)-1; i++ {
		if cmp := decimal.NewFromFloat(baseInfo[i].Close).Cmp(decimal.NewFromFloat(lowest30Price)); cmp <= 0 {
			lowest30Price = baseInfo[i].Close
		}
	}

	cmp1 := decimal.NewFromFloat(todayInfo.Close).Div(decimal.NewFromFloat(lowest30Price))
	if res := cmp1.Cmp(decimal.NewFromFloat(1.05)); res <= 0 {
		return true
	}
	return false
}

/**计算十字星
1.开盘价相比较收盘价在0.02元以内
2.或者开盘价相比较收盘价振幅在0.1%内
*/
func CalculateTagDojiLine(baseInfo []BaseAnalyseInfo) bool {
	if len(baseInfo) == 0 {
		return false
	}
	todayInfo := baseInfo[len(baseInfo)-1]

	if -0.01 <= todayInfo.Close-todayInfo.Open && todayInfo.Close-todayInfo.Open <= 0.01 {
		return true
	}

	div := decimal.NewFromFloat(todayInfo.Close).Div(decimal.NewFromFloat(todayInfo.Open))
	cmp1 := div.Cmp(decimal.NewFromFloat(1.001))
	cmp2 := div.Cmp(decimal.NewFromFloat(0.999))
	if cmp1 == -1 && cmp2 == 1 {
		return true
	}
	return false
}

/**计算多十字星（最近5天，有两天及以上收十字星）
1.开盘价相比较收盘价在0.02元以内
2.或者开盘价相比较收盘价振幅在0.1%内
*/
func CalculateTagContinueDojiLine(baseInfo []BaseAnalyseInfo) bool {
	if len(baseInfo) < 2 {
		return false
	}

	compareCount := 2
	totalDay := 0

	for i := len(baseInfo) - compareCount; i < len(baseInfo); i++ {
		todayInfo := baseInfo[i]
		if -0.01 <= todayInfo.Close-todayInfo.Open && todayInfo.Close-todayInfo.Open <= 0.01 {
			totalDay++
			continue
		}

		div := decimal.NewFromFloat(todayInfo.Close).Div(decimal.NewFromFloat(todayInfo.Open))
		cmp1 := div.Cmp(decimal.NewFromFloat(1.001))
		cmp2 := div.Cmp(decimal.NewFromFloat(0.999))
		if cmp1 == -1 && cmp2 == 1 {
			totalDay++
			continue
		}
	}

	if totalDay == 2 {
		return true
	}
	return false
}
